#pragma once
#define _USE_MATH_DEFINES
#include "precom.h"
#include <commdlg.h>
#include "BaseWindow.h"

#include <fcntl.h>
#include <sys/types.h>
#include <string.h>
#include <io.h>
#include <cmath>

#include "freetype.h"
//#include "CamEye.h"
#include "ArcBall.h"
#include "Core.h"
#include "ShaderManager.h"
#include "Dialogs.h"
//#include "../Math/fmtxlib.h"

enum SIDES {FRONT, BACK, LEFT, RIGHT, TOP, BOTTOM};
enum STEERING {
	MOVE_UP			= 0,
	MOVE_DOWN		= 1,
	MOVE_LEFT		= 2,
	MOVE_RIGHT		= 3,
	MOVE_FORWARD	= 4,
	MOVE_BACKWARD	= 5,
	ROTATE_UP		= 6,
	ROTATE_DOWN		= 7,
	ROTATE_LEFT		= 8,
	ROTATE_RIGHT	= 9,
	ROTATE_CW		= 10,
	ROTATE_CCW		= 11,
	MOVE_TOOL_UP	= 12,
	MOVE_TOOL_DOWN	= 13,
	MOVE_TOOL_LEFT	= 14,
	MOVE_TOOL_RIGHT = 15,
	MOVE_TOOL_FORWARD	= 16,
	MOVE_TOOL_BACKWARD	= 17,
	ROTATE_TOOL_DOWN	= 18,
	ROTATE_TOOL_UP		= 19,
	ROTATE_TOOL_LEFT	= 20,
	ROTATE_TOOL_RIGHT	= 21,
	ZOOM_IN				= 22,
	ZOOM_OUT			= 23,
	STEERING_ENUM_COUNT	= 24
};

#define SCREEN_DEPTH 16

class MainWindow : public BaseWindow
{
private:
	float			fps;
	unsigned int	tick;
	unsigned int	countFrame;
	unsigned long	m_debugNum;
	GLint			viewport[4];
	GLdouble		modelview[16];
	GLdouble		projection[16];
	fmath::matrix44	persp;
	bool			timerOn;
	bool			m_keys[STEERING_ENUM_COUNT];

	POINT			mousePosR, mousePosL;
	FPSData			m_fpsData;
	freetype::font_data	ourFont;

    //Zmienne zalezne od programu a nie szkieletu
    
    //Metody zalezne od programu a nie szkieletu
	void SetLights(const Box& a_box);
	void DrawExample();
	void DrawBackground();
	char* ReadShaderTxtFile(const char* ) ;
	//GLint GetUniLoc(GLuint program, const GLchar* name) const;

	//===================================
	//	SHADERY
	ShaderManager m_shaderManager;
	fmath::vector3 m_lights[8];

	Model	modelik;
	Core	m_core;
	bool	m_showNormals, m_extraZoom, m_showModel,
		m_showBoundingTool, m_drawPath, m_debugView,
		m_showSurface;
	bool	m_play;
	unsigned short m_showIntersectingCubes;
	unsigned long m_pathDensity;
protected:
//	CamEye	cam;
	ArcBall camera;
	Dialogs m_dialog;

	void	reinitWndScreenData();
	void	StartTimer();
	void	StopTimer();
	void	DrawFPS();
	void	DrawPath5C(const Path5C& a_path, unsigned long a_density, const fmath::vector3& a_color) const;
	
    //Metody zalezne od programu a nie szkieletu
	long 	OpenFileDlg(wchar_t* a_filtr, wchar_t* a_fileName, long a_nameSize);
	long 	SaveFileDlg(wchar_t* a_filtr, wchar_t* a_fileName, long a_nameSize);
	void	SaveRaport();
	void	SavePath();
	void	OpenModel();
	void	OpenPath();
	void	KeyMap(WPARAM wParam, bool isDown);
	void	DoWhatKeysShouldDo();
	void	ChangeSPMethod(int a_methodID);

	inline void OnOffBoundingTool()
	{ m_showBoundingTool = !m_showBoundingTool; }
	inline void OnOffModel()
	{ 
		if(m_showModel && m_showSurface)
			m_showModel = false; 
		else if(m_showModel)
			m_showSurface = true;
		else {
			m_showSurface = false;
			m_showModel = true; 
		}
	}
	inline void OnOffExtraZoom()
	{ m_extraZoom = !m_extraZoom; }
	inline void OnOffDebugView()
	{ 
		m_debugView = !m_debugView; 
		if(m_debugView 
			&& (m_core.GetMethodID() == NUMERICAL_DERIVATIVE))
			ShowWindow(hWndD, SW_SHOW);
		else
			ShowWindow(hWndD, SW_HIDE);
		SetActiveWindow(hWnd);
	}
	inline void OnOffNormals()
	{ m_showNormals = !m_showNormals; }
	inline void OnOffCubes()
	{ if(++m_showIntersectingCubes > 2) m_showIntersectingCubes = 0; }

	inline void PathDensityChange(long val) { 
		m_pathDensity += val; 
		if(m_pathDensity == 0 || m_pathDensity > 10000) 
			m_pathDensity = 1;
	}
public:
	MainWindow(HINSTANCE hInastance);

	void	InitGL();
	void	InitGLInDebugView();
	void	Draw();
	void	DebugDraw();
	void	SizeChanged();
	void	OnInit(HWND& a_hWnd, HDC& a_hDC, HGLRC& a_hRC, int a_layer);
	void	OnCreate();
    void	OnWmCreate();
	void	OnWmDebugCreate();
	void	OnDestroy();
	void	OnDebugDestroy();
	void	OnMenuChoosed(WPARAM wParam);
	void	OnToolbarTip(LPARAM lParam);
	void	OnToolbarChoosed(WPARAM wParam);
	void	OnLButtonDown(WPARAM wParam, LPARAM lParam);
	void	OnRButtonDown(WPARAM wParam, LPARAM lParam);
	void	OnLButtonUp(WPARAM wParam, LPARAM lParam);
	void	OnRButtonUp(WPARAM wParam, LPARAM lParam);
	void	OnMouseMove(WPARAM wParam, LPARAM lParam);
	void	OnMouseWheel(WPARAM wParam, LPARAM lParam);
	void	OnKeyDown(WPARAM wParam);
	void	OnDebugKeyDown(WPARAM wParam);
	void	OnKeyUp(WPARAM wParam);
	void	OnTimerMethod();
	void	Update();

    //Metody zalezne od programu a nie szkieletu
};